package com.gxc.linkedList;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 复制带随机指针的链表
 * 给你一个长度为 n 的链表，每个节点包含一个额外增加的随机指针 random ，该指针可以指向链表中的任何节点或空节点。
 *
 * 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成，其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点，并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
 *
 * 例如，如果原链表中有 X 和 Y 两个节点，其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ，同样有 x.random --> y 。
 *
 * 返回复制链表的头节点。
 *
 * 用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示：
 *
 * val：一个表示 Node.val 的整数。
 * random_index：随机指针指向的节点索引（范围从 0 到 n-1）；如果不指向任何节点，则为  null 。
 * 你的代码 只 接受原链表的头节点 head 作为传入参数。
 */
public class CopyRandomList {

    public static void main(String[] args) {
        ListNode head1 = new ListNode(7);
        ListNode head2 = new ListNode(13);
        ListNode head3 = new ListNode(11);
        ListNode head4 = new ListNode(10);
        ListNode head5 = new ListNode(1);
        head1.next = head2;
        head2.next = head3;
        head2.random = head1;
        head3.next = head4;
        head3.random = head5;
        head4.next = head5;
        head4.random = head3;
        head5.random = head1;

        handle2(head1);
        System.out.println("");
    }

    /**
     * 使用额外空间map保存node，
     * 两次遍历建立关联
     * @param head
     * @return
     */
    public ListNode handle(ListNode head) {
        Map<ListNode, ListNode> map = new HashMap<>();

        ListNode node = head;
        while (node != null) {
            map.put(node, new ListNode(node.val));
            node = node.next;
        }
        node = head;
        while (node != null) {
            ListNode listNode = map.get(node);
            listNode.next = map.get(node.next);
            listNode.random = map.get(node.random);

            node = node.next;
        }
        return map.get(head);
    }

    /**
     * 不适用额外空间
     * 在原先的节点后复制原有的节点的复制
     * @param head
     * @return
     */
    public static ListNode handle2(ListNode head) {
        if (head == null) return null;
        ListNode cur = head;
        while (cur != null) {
            ListNode listNode = new ListNode(cur.val);
            listNode.next = cur.next;
            cur.next = listNode;
            cur = cur.next.next;
        }

        for (ListNode node = head; node != null; node = node.next.next) {
            ListNode nodeNew = node.next;
            nodeNew.random = (node.random != null) ? node.random.next : null;
        }
        ListNode headNew = head.next;
        for (ListNode node = head; node != null; node = node.next) {
            ListNode nodeNew = node.next;
            node.next = node.next.next;
            nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
        }
        return headNew;
    }



    public static class ListNode {
        int val;
        CopyRandomList.ListNode next;
        CopyRandomList.ListNode random;
        ListNode() {}
        ListNode(int val) { this.val = val; }
    }


}
